package es.bwain.xprt.errors;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import es.bwain.xprt.action.Initializer;

public class XprtError {

	private static final String nl = System.getProperty("line.separator");
	
	public static String getError(Throwable aThrowable, HttpServletRequest request, String xsltFile) {
		StringBuffer sb = new StringBuffer();

		sb.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">" + nl);
		sb.append("<html>" + nl);
		sb.append("<head>" + nl);
		sb.append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">" + nl);
		sb.append("<title>An error has occurred</title>" + nl);

		sb.append("<style>" + nl);
		sb.append("body, h1, h2, h3, p, li {" + nl);
		sb.append("font-family: Arial, sans-serif;" + nl);
		sb.append("font-size: 12px;" + nl);
		sb.append("margin: 0px;" + nl);
		sb.append("}" + nl);
		sb.append("body {" + nl);
		sb.append("margin: 10px;" + nl);
		sb.append("}" + nl);
		sb.append("h1 {" + nl);
		sb.append("margin-bottom: 10px;" + nl);
		sb.append("font-size: 48px;" + nl);
		sb.append("}" + nl);
		sb.append("h2 {" + nl);
		sb.append("font-size:14px;" + nl);
		sb.append("}" + nl);
		sb.append("h3 {" + nl);
		sb.append("margin-bottom: 6px;");
		sb.append("font-size: 11px;" + nl);
		sb.append("}" + nl);
		sb.append("#stacktrace {" + nl);
		sb.append("font-size: 10px;" + nl);
		sb.append("background-color: #FFFF88;" + nl);
		sb.append("padding: 10px;" + nl);
		sb.append("border: 1px solid #C79810;" + nl);
		sb.append("overflow: hidden;" + nl);
		sb.append("}" + nl);
		
		sb.append("#foot {" + nl);
		sb.append("font-size: 11px;" + nl);
		sb.append("background-color: #DDDDDD;" + nl);
		sb.append("padding: 5px;" + nl);
		sb.append("margin-top: 10px;" + nl);
		sb.append("overflow: hidden;" + nl);
		sb.append("}" + nl);
		
		sb.append("div.code {" + nl);
		sb.append("font-family: Courier New, Courier, monoespace;" + nl);
		sb.append("font-size: 11px;" + nl);
		sb.append("padding: 5px;" + nl);
//		sb.append("margin-top: 10px;" + nl);
		sb.append("overflow: hidden;" + nl);
		sb.append("}" + nl);
		
		sb.append("</style>" + nl);

		sb.append("</head>" + nl);
		sb.append("<body>" + nl);

		sb.append("<h1>Whoops!</h1>" + nl);
		
		if (aThrowable instanceof ClassNotFoundException) {
			sb.append("<h2>It seems that you are here due to one of these reasons:</h2>" + nl);
			sb.append("<ol>");
			sb.append("<li>You have misspelled the web address, or...</li>");
			sb.append("<li>You forgot to create the Class: <strong>" + aThrowable.getMessage() + ".java</strong>, or...</li>");
			if (request.getParameter(Initializer.getDirectToMethodParam()) == null) {
				sb.append("<li>You forgot to create the XSLT file: <strong>" + xsltFile + "</strong></li>");
			} else {
				sb.append("<li>Try to remove the parameter <strong>" + Initializer.getDirectToMethodParam() + "</strong> if you have created the XSLT file: <strong>" + xsltFile + "</strong></li>");
			}
			sb.append("</ol>");
			
			if (request.getParameter(Initializer.getDirectToMethodParam()) != null) {
				sb.append("<p><strong>Important:</strong> To call a specific method instead of the default one then you need to create the Class.</p><br/>");
			}
			
			
		} else if (aThrowable instanceof NoSuchMethodException) {
			sb.append("<h2>It seems that you are here due to one of these reasons:</h2>" + nl);
			sb.append("<ol>");
			sb.append("<li>You have misspelled the name of method in the parameter: <strong>" + Initializer.getDirectToMethodParam() + "</strong>, or...</li>");
			sb.append("<li>You forgot to create the method: <strong>" + request.getParameter(Initializer.getDirectToMethodParam())  + "</strong>, make sure it is well formed: <br/>");
			sb.append("<div class=\"code\">public void <strong>" + request.getParameter(Initializer.getDirectToMethodParam()) + "(HttpServletRequest request, HttpServletResponse response)</strong> {<br/>//...<br/>}</div></li>");
			sb.append("</ol>");
			
		} else if (aThrowable instanceof IllegalAccessException) {
			sb.append("<h2>It seems that you are here due to this reason:</h2>" + nl);
			sb.append("<ul>");
			sb.append("<li>The defined method is not public, make sure it is well formed: <br/>");
			sb.append("<div class=\"code\"><strong>public</strong> void " + request.getParameter(Initializer.getDirectToMethodParam()) + "(HttpServletRequest request, HttpServletResponse response) {<br/>//...<br/>}</div></li>");
			sb.append("</ul>");
			
		} else {
			sb.append("<h2>I have no idea why you're here.</h2>" + nl);
			sb.append("<ul>");
			sb.append("<li>Please see the stack trace for more info.</li>");
			sb.append("</ul>");
		}
		
		sb.append(XprtError.getCustomStackTrace(aThrowable));
		
		sb.append("<div id=\"foot\">" + nl);
		sb.append("<strong>" + Initializer.getVersion() + "</strong> by Ricardo Pastor." + nl);
		sb.append("</div>" + nl);
		
		sb.append("</body>" + nl);
		sb.append("</html>" + nl);
		
		return sb.toString();

	}

	public static String getCustomStackTrace(Throwable aThrowable) {
		// add the class name and any message passed to constructor
		final StringBuilder result = new StringBuilder();
		result.append("<div id=\"stacktrace\">");
		result.append("<h3>" + aThrowable.toString() + "</h3>" + nl);
		// add each element of the stack trace
		for (StackTraceElement element : aThrowable.getStackTrace()) {
			result.append(element + "<br/>" + nl);
		}
		result.append("</div>");
		return result.toString();
	}
	
	public static void write(Throwable aThrowable, HttpServletRequest request, HttpServletResponse response) throws IOException {
		write(aThrowable, request, response, null);
	}
	
	public static void write(Throwable aThrowable, HttpServletRequest request, HttpServletResponse response, String xsltFile) throws IOException {
		response.setStatus(500);
		response.getOutputStream().write(XprtError.getError(aThrowable, request, xsltFile).getBytes());
	}

}
